package edu.utexas.ipc;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.IOException;
import java.net.Socket;
import java.util.StringTokenizer;

class Linker {

	final int processID;
	final int processCount;
	BufferedWriter[] writer;
	BufferedReader[] reader;
	Socket[] socket;
	
	Linker(int processID, int processCount) {
		this.processID = processID;
		this.processCount = processCount;
		this.writer = new BufferedWriter[processCount];
		this.reader = new BufferedReader[processCount];
		this.socket = new Socket[processCount];
	}
	
	void sendMessage(int destID, String tag, String timestamp, String message) {
		try {
			if (isConnected(destID)) {
				writer[destID].write(processID + " " + destID + " " + tag + " " + timestamp + " " + message + "#\n");
				writer[destID].flush();
			}
		} catch (IOException e) {
			closeConnection(destID);
		}
	}
	
	void sendMessage(int destID, String timestamp, String tag) {
		sendMessage(destID, tag, timestamp, "");
	}
	
	void broadcast(String tag, String timestamp, String message) {
		for (int destID = 0; destID < processCount; destID++) {
			sendMessage(destID, tag, timestamp, message);
		}
	}
	
	Message receiveMessage(int sourceID) {
		try {
			String line = reader[sourceID].readLine();
			if (line == null) {
				closeConnection(sourceID);
				return null;
			}

			StringTokenizer st = new StringTokenizer(line);
			int srcID = Integer.parseInt(st.nextToken());
			int destID = Integer.parseInt(st.nextToken());
			String tag = st.nextToken();
			String ts = st.nextToken();
			String app = st.nextToken("#").trim();

			return new Message(srcID, destID, tag, ts, app);
		} catch (IOException e) {
			closeConnection(sourceID);
			return null;
		}
	}
	
	void close() {
		for (int id = 0; id < processCount; id++) {
			closeConnection(id);
		}
	}
	
	boolean isConnected(int destID) {
		return socket[destID] != null && !socket[destID].isClosed();
	}
	
	int getProcessID() {
		return processID;
	}
	
	void closeConnection(int id) {
		try {
			if (socket[id] != null) socket[id].close();
			if (writer[id] != null) writer[id].close();
			if (reader[id] != null) reader[id].close();
		} catch (IOException e) {
			e.printStackTrace();
		}	
	}
	
	void setupLink(int peerID, Socket sckt, BufferedReader in, BufferedWriter out) {
		socket[peerID] = sckt;
		reader[peerID] = in;
		writer[peerID] = out;
	}
}
